package com.apobates.jforum.grief.schema2doc.jdbc.dialect;

import com.apobates.jforum.grief.schema2doc.core.SchemaTableStrategy;
import com.apobates.jforum.grief.schema2doc.core.entity.Column;
import com.apobates.jforum.grief.schema2doc.core.entity.Nullable;
import com.apobates.jforum.grief.schema2doc.core.entity.PrimayKey;
import com.apobates.jforum.grief.schema2doc.core.entity.Table;
import com.apobates.jforum.grief.schema2doc.jdbc.schema.AbstractQueryExecutor;
import com.apobates.jforum.grief.schema2doc.core.schema.SchemaDialect;
import org.jooq.DSLContext;
import org.jooq.impl.DSL;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;
import java.util.Optional;
import java.util.stream.Stream;
/**
 * MariaDB的结果集供应商
 */
public class JooqQueryMariaDBExecutor extends AbstractQueryExecutor {
    private final static Logger logger = LoggerFactory.getLogger(JooqQueryMariaDBExecutor.class);

    public JooqQueryMariaDBExecutor(DataSource dataSource, SchemaDialect dialect) {
        super(dataSource, dialect);
    }

    @Override
    protected Stream<Table> getTables(DSLContext context, Optional<String> dbName, Optional<String> schema, SchemaTableStrategy tableStrategy) throws IllegalArgumentException {
        // https://mariadb.com/kb/en/information-schema-tables-table/
        String sql = "SELECT TABLE_NAME AS tableName, TABLE_COMMENT AS remarks FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = :dbname";
        if(tableStrategy.sql(SchemaDialect.MariaDB).isPresent()){
            sql+= " AND " + tableStrategy.sql(SchemaDialect.MariaDB).get().replaceAll(SchemaTableStrategy.placeholder, "TABLE_NAME");
        }
        logger.debug("[TABLE-MariaDB]execute sql statement::"+sql);
        return context.fetch(sql, DSL.param("dbname", dbName.get())).stream().map(record -> {
            // String dbName, String tableName, String remarks
            return Table.noSchema(
                    0,
                    dbName.get(),
                    record.get("tableName", String.class),
                    record.get("remarks", String.class));
        }).filter(table->tableStrategy.filter().test(table.getTableName()));
    }

    @Override
    protected Stream<Column> getColumns(DSLContext context, Table table) {
        // https://mariadb.com/kb/en/information-schema-columns-table/
        String sql = "SELECT " +
                "COLUMN_NAME AS columnName, " +
                "DATA_TYPE AS typeName, " +
                "REPLACE(REPLACE(REPLACE(COLUMN_TYPE, DATA_TYPE, ''), '(', ''), ')', '') AS columnSize, " +
                "IF(IS_NULLABLE='NO','2','1') AS nullable, " +
                "COLUMN_COMMENT AS remarks, " +
                "COLUMN_DEFAULT AS columnDef, " +
                "IF(COLUMN_KEY='PRI','1','2') AS pk, " +
                "NUMERIC_SCALE AS decimalDigits " +
                "FROM INFORMATION_SCHEMA.COLUMNS " +
                "WHERE TABLE_SCHEMA = :dbname AND TABLE_NAME = :tablename";
        logger.debug("[COLUMN-MariaDB]execute sql statement::"+sql);
        // Fetch results using jOOQ
        return context.fetch(sql, DSL.param("dbname", table.getDbName()), DSL.param("tablename", table.getTableName())).stream().map(record -> {
            // Basic:: String columnName, String typeName, String columnSize, Nullable nullable, String remarks
            return Column.basic(
                            record.get("columnName", String.class),
                            record.get("typeName", String.class),
                            record.get("columnSize", String.class),
                            Nullable.of(record.get("nullable", Integer.class)),
                            record.get("remarks", String.class))
                    .toFull(
                            record.get("decimalDigits", String.class),
                            PrimayKey.of(record.get("pk", Integer.class)),
                            record.get("columnDef", String.class)); // String decimalDigits, PrimayKey pk, String columnDef
        });
    }
}
